#![allow(warnings)]
use std::{rc::Rc, cell::RefCell, fs::{File, OpenOptions}, io::Write, sync::{Mutex, Arc}, time::Instant, backtrace::Backtrace, panic::{PanicInfo, Location}};


use once_cell::sync::Lazy;

use crate::{rtda::{Thread, Frame}, instructions::{factory, base::Instruction}, instructions::{base, MONITOR_LOCKS}};


pub fn interpret(thread: Arc<Mutex<Thread>>, log_inst: bool) {
    // 处理panic
    let result = std::panic::catch_unwind(|| {
        _loop(thread.clone(), log_inst);
        
        // 线程执行后应当不在持有锁
        if !thread.lock().unwrap().locks().is_empty() {
            panic!("线程存在未释放的锁");
        }
    });

    if let Err(err) = result {  
        let panic_info = match (err.downcast_ref::<&str>(), err.downcast_ref::<&String>()) {  
            (Some(info), None) => *info,  
            (None, Some(info))=> *info,  
            (Some(info1), Some(info2))=> *info1,  
            _ => "panic信息转换失败",  
        };

        // 释放线程持有的所有锁
        let thread_ref = thread.lock().unwrap();
        let locks = thread_ref.locks();
        let mut map = MONITOR_LOCKS.lock().unwrap();
        for key in locks.iter() {
            let lock = map.get(key).unwrap().clone();
            lock.release_lock();
        }
        drop(map);
        drop(thread_ref);

        println!("Exception in thread xxx {}", panic_info); 
        log_frames(thread.clone());

    } 
}

pub(crate) static LINE: Lazy<Mutex<usize>> = Lazy::new(|| Mutex::new(0));

pub fn _loop(thread: Arc<Mutex<Thread>>, log_inst: bool) {
    while !thread.lock().unwrap().is_stack_empty() {
        let mut reader = base::BytecodeReader::new();
        let frame = thread.lock().unwrap().current_frame();
        let pc = frame.borrow().get_next_pc();
        thread.lock().unwrap().set_pc(pc as i32);
        // decode
        let method = frame.borrow().get_method();
        reader.reset(method.get_code(), pc);
        let opcode = reader.read_u8();
        let mut inst = factory::new_instruction(opcode);
        inst.fetch_operands(&mut reader);
        frame.borrow_mut().set_next_pc(reader.get_pc());

        if log_inst {
            *LINE.lock().unwrap() += 1;
            log_instruction(frame.clone(), &inst);
            // show_frames(thread.lock().unwrap().get_frames());
        }
        // 执行时间开始
        // let start_time = Instant::now();
        // let s = instruction(frame.clone(), &inst);

        // execute
        inst.execute(frame);

        // execution_time(start_time, s);        
    }
}

fn instruction(frame: Rc<RefCell<Frame>>, inst: &Box<dyn Instruction>) -> String {
    let method = frame.borrow().get_method();
    let class_name = method.get_class().get_name();
    let method_name = method.get_name();
    let pc = frame.borrow().get_thread().lock().unwrap().get_pc();
    format!("{}.{}() {} {:?}", class_name, method_name, pc, inst)
}

fn log_instruction(frame: Rc<RefCell<Frame>>, inst: &Box<dyn Instruction>) {
    let method = frame.borrow().get_method();
    let class_name = method.get_class().get_name();
    let method_name = method.get_name();
    let method_descriptor = method.get_descriptor();
    let pc = frame.borrow().get_thread().lock().unwrap().get_pc();

    println!("line: {} {}.{}{} {} {:?}", *LINE.lock().unwrap(), class_name, method_name, method_descriptor, pc, inst);
}

pub fn log_frames(thread: Arc<Mutex<Thread>>) {
    let mut thread = thread.lock().unwrap();
    while !thread.is_stack_empty() {
        let frame = thread.pop_frame();
        let method = frame.borrow().get_method();
        let class_name = method.get_class().get_name();
        let line_num = method.get_line_number(frame.borrow().get_next_pc() as i32);
        println!(">> line:{} pc:{} {}.{}{} \n", line_num, frame.borrow().get_next_pc(), class_name, method.get_name(), method.get_descriptor());
    }
}

fn show_frames(frames: Vec<Rc<RefCell<Frame>>>) {
    for frame in  frames {
        let method = frame.borrow().get_method();
        let class_name = method.get_class().get_name();
        let line_num = method.get_line_number(frame.borrow().get_next_pc() as i32);
        println!(">> line:{} pc:{} {}.{}{} ", line_num, frame.borrow().get_next_pc(), class_name, method.get_name(), method.get_descriptor());
    }
    println!("");
}

pub fn execution_time(start_time: Instant, info: String) {
    let end_time = Instant::now();
    // 计算方法的执行时间  
    let duration = end_time - start_time;  

    // 打印方法的执行时间（以纳秒为单位）  
    println!("line: {} {}ms {}\n", LINE.lock().unwrap(), duration.as_nanos() / 1_000_000, info);  
}